home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Freeware / Griffith 0.9.8 / griffith-0.9.8-win32.exe / {app} / lib / plugins / imp / CSV.py < prev   
Text File  |  2008-11-17  |  13KB  |  415 lines

  1. # -*- coding: UTF-8 -*-
  2.  
  3. __revision__ = '$Id: CSV.py 1040 2008-11-15 21:13:49Z mikej06 $'
  4.  
  5. ###########################################################################
  6. #    Copyright (C) 2006-2007 by Jessica Katharina Parth                         
  7. #    <Jessica.K.P@women-at-work.org>                                       
  8. #
  9. # Copyright: See COPYING file that comes with this distribution
  10. #
  11. ###########################################################################
  12.  
  13. from plugins.imp import ImportPlugin as IP
  14. import gtk
  15. import gtk.glade
  16. import os
  17. import pygtk
  18. import sys
  19. import gutils
  20. import string
  21.  
  22.  
  23. def digits_only(s):
  24.     import string, re
  25.     _match = re.compile(r"\d+")
  26.     try:
  27.         s = reduce( string.join, _match.findall(s) )
  28.     except:
  29.         s = '0'
  30.     return s
  31.     
  32. def letters_only(s):
  33.     import string, re
  34.     _match = re.compile(r"\D+")
  35.     try:
  36.         s = reduce( string.join, _match.findall(s) )
  37.     except:
  38.         s = s
  39.     return s
  40.     
  41. class ImportPlugin(IP):
  42.     description    = _("Full CSV list import plugin")
  43.     author        = "Jessica Katharina Parth"
  44.     email        = "Jessica.K.P@women-at-work.org"
  45.     version        = "0.3"
  46.     file_filters    = '*.[cC][sS][vV]'
  47.     mime_types    = ('text/comma-separated-values', 'text/csv', 'application/csv')
  48.  
  49.     def initialize(self):
  50.         if not IP.initialize(self):
  51.             return False
  52.         # glade
  53.         gf = os.path.join(self.locations['glade'], 'importcsv.glade')
  54.         # try to open the glade file
  55.         try:
  56.             self.gtk = gtk.glade.XML(gf)
  57.         except:
  58.             self.debug.show("Glade-file %s can not be loaded." % gf)
  59.             return False
  60.         # open gtk window
  61.         self.gtk.get_widget('d_import').set_transient_for( self.widgets['window'] )
  62.         
  63.         # simple string lists
  64.         self.tv_csv = self.gtk.get_widget('tv_csv')
  65.         self.tv_assigned = self.gtk.get_widget('tv_assigned')
  66.         self.tv_griffith = self.gtk.get_widget('tv_griffith')
  67.         
  68.         # 1st list
  69.         self.ls_csv = gtk.ListStore(str)
  70.         self.tv_csv.set_model(self.ls_csv)
  71.         renderer = gtk.CellRendererText()
  72.         column = gtk.TreeViewColumn("none", renderer, text=0)
  73.         self.tv_csv.append_column(column)
  74.         
  75.         # 2nd list 
  76.         self.ls_griffith = gtk.ListStore(str,str)
  77.         self.tv_griffith.set_model(self.ls_griffith)
  78.         renderer = gtk.CellRendererText()
  79.         column = gtk.TreeViewColumn("none", renderer, text=0)
  80.         column.set_visible(False)
  81.         self.tv_griffith.append_column(column)
  82.         column = gtk.TreeViewColumn("none", renderer, text=1)
  83.         self.tv_griffith.append_column(column)
  84.         self.set_griffith_fields()
  85.         
  86.         # 3rd list
  87.         self.ls_assigned = gtk.ListStore(str,str,str)
  88.         self.tv_assigned.set_model(self.ls_assigned)
  89.         renderer = gtk.CellRendererText()
  90.         column = gtk.TreeViewColumn("none", renderer, text=0)
  91.         self.tv_assigned.append_column(column)
  92.         # add the columns for internal information handling and hide them
  93.         column = gtk.TreeViewColumn("none", renderer, text=1)
  94.         column.set_visible(False)
  95.         self.tv_assigned.append_column(column)
  96.         column = gtk.TreeViewColumn("none", renderer, text=2)
  97.         column.set_visible(False)
  98.         self.tv_assigned.append_column(column)
  99.     
  100.         # hide tabs
  101.         self.nb_pages = self.gtk.get_widget('nb_pages')
  102.         self.nb_pages.get_nth_page(1).hide()
  103.         self.nb_pages.connect("switch-page", self._on_page_changed)
  104.         
  105.         # Events
  106.         # Buttons
  107.         self.b_cancel = self.gtk.get_widget("b_cancel")
  108.         self.b_cancel.connect("clicked", self._clicked)
  109.         
  110.         self.b_next = self.gtk.get_widget("b_next")
  111.         self.b_next.connect("clicked", self._clicked)
  112.         
  113.         self.b_back = self.gtk.get_widget("b_back")
  114.         self.b_back.connect("clicked", self._clicked)
  115.         
  116.         self.b_add = self.gtk.get_widget("b_add")
  117.         self.b_add.connect("clicked", self._clicked)
  118.         
  119.         self.b_del = self.gtk.get_widget("b_del")
  120.         self.b_del.connect("clicked", self._clicked)
  121.         
  122.         # Treeviews
  123.         self.tv_griffith.connect("row_activated", self._on_row_activated)
  124.         self.tv_griffith.connect("cursor_changed", self._on_cursor_changed)
  125.         self.tv_csv.connect("row_activated", self._on_row_activated)
  126.         self.tv_csv.connect("cursor_changed", self._on_cursor_changed)
  127.         self.tv_assigned.connect("cursor_changed", self._on_cursor_changed)
  128.         
  129.         self.gtk.get_widget('e_lineterminator').set_active(0)
  130.         
  131.         self.selected_griffith = None
  132.         self.selected_csv = None
  133.         self.current_csv_row = 0
  134.         self.csv_header = None
  135.         return True
  136.     
  137.     def set_griffith_fields(self):
  138.         # 2nd list
  139.         sorted_list = ( "number", "title", "o_title", "director", "year", "country",
  140.                 "cast", "studio", "plot", "runtime", "genre", "classification",
  141.                 "site", "o_site", "trailer", "image", "seen", "loaned", "notes",
  142.                 "rating", "movie_id", "collection_id", "volume_id", "medium_id",
  143.                 "vcodec_id", "color", "cond", "layers", "region", "media_num" )
  144.         # sort the list and add field and translated field-name
  145.         for sorted in sorted_list:
  146.             for name in self.fields_to_import:
  147.                 if sorted == name:
  148.                     iterator = self.ls_griffith.append()
  149.                     self.ls_griffith.set_value(iterator, 0, name)
  150.                     self.ls_griffith.set_value(iterator, 1, self.fields[name])
  151.  
  152.     def create_import_table(self):
  153.         self.import_table = {}
  154.         item = self.ls_assigned.get_iter_first()
  155.         while item is not None:
  156.             self.import_table[self.ls_assigned.get_value(item,1)] = self.ls_assigned.get_value(item,2)
  157.             item = self.ls_assigned.iter_next(item)
  158.             
  159.     def _on_page_changed(self, notebook, page, page_num):
  160.         if page_num == 0:
  161.             self.b_back.set_sensitive(False)
  162.         if page_num == 1:
  163.             self.b_back.set_sensitive(True)
  164.             self.open_source()
  165.             
  166.         
  167.     def _clicked(self, widget, event=None, data=None):
  168.         if widget == self.b_cancel:
  169.             self.gtk.get_widget('d_import').hide()
  170.             self.gtk.get_widget('d_import').response(gtk.RESPONSE_CANCEL)
  171.             
  172.         if widget == self.b_back:
  173.             if self.nb_pages.get_current_page() == 1:
  174.                 self.nb_pages.prev_page()
  175.  
  176.         if widget == self.b_next:
  177.             if self.nb_pages.get_current_page() == 0:
  178.                 self.nb_pages.get_nth_page(1).show()
  179.                 self.nb_pages.next_page()
  180.             else:
  181.                 if self.nb_pages.get_current_page() == 1:
  182.                     # test if at least one field is assigned
  183.                     if self.ls_assigned.get_iter_first() is not None:
  184.                         # prepare tabelle for import
  185.                         self.create_import_table()
  186.                             
  187.                         # hide everything
  188.                         self.gtk.get_widget('d_import').hide()
  189.                         self.gtk.get_widget('d_import').response(gtk.RESPONSE_OK)
  190.                     else:
  191.                         gutils.info(self.gtk, _("Please assign at least one field first!"), self.gtk.get_widget('d_import') )
  192.                         
  193.         if widget == self.b_add:
  194.             iterator = self.ls_assigned.append()
  195.             self.ls_assigned.set_value(iterator, 0, "%s > %s" % (self.selected_csv, self.fields[self.selected_griffith]) )
  196.             # add information for the import tabelle
  197.             self.ls_assigned.set_value(iterator, 1, self.selected_griffith )
  198.             self.ls_assigned.set_value(iterator, 2, str(self.csv_header.index(self.selected_csv)) )
  199.             self.ls_griffith.remove(self.iter_griffith)
  200.             self.selected_griffith = None
  201.             
  202.             self.b_add.set_sensitive(False)
  203.         
  204.         if widget == self.b_del:
  205.             # re-add field to griffith
  206.             field_name = self.ls_assigned.get_value(self.iter_assigned,1)
  207.  
  208.             iterator = self.ls_griffith.append()
  209.             self.ls_griffith.set_value(iterator, 0, field_name)
  210.             self.ls_griffith.set_value(iterator, 1, self.fields[field_name])
  211.             
  212.             # remove assigned row
  213.             self.ls_assigned.remove(self.iter_assigned)
  214.             
  215.             self.b_del.set_sensitive(False)
  216.             
  217.                     
  218.     def _on_row_activated(self, treeview, path, view_column, data = None):
  219.         # get selected rows from both treeviews/lists
  220.         if treeview == self.tv_griffith:
  221.             self.iter_griffith = self.ls_griffith.get_iter(path)
  222.         
  223.             if self.iter_griffith:
  224.                 self.selected_griffith = self.ls_griffith.get_value(self.iter_griffith,0)
  225.         
  226.         if treeview == self.tv_csv:
  227.             iter = self.ls_csv.get_iter(path)
  228.         
  229.             if iter:
  230.                 self.selected_csv = self.ls_csv.get_value(iter,0)
  231.                 
  232.         # enable add button if both lists have a selected item
  233.         if self.selected_griffith is not None and self.selected_csv is not None:
  234.             self.b_add.set_sensitive(True)
  235.         else:
  236.             self.b_add.set_sensitive(False)
  237.         
  238.     def _on_cursor_changed(self, widget, data1 = None, data2 = None):
  239.         # get selected rows from both treeviews/lists
  240.         selection = widget.get_selection()
  241.         (model,iter) = selection.get_selected()
  242.             
  243.         if widget == self.tv_griffith:
  244.             self.iter_griffith = iter
  245.             if self.iter_griffith:
  246.                 self.selected_griffith = str(model.get_value(self.iter_griffith, 0))
  247.             else:
  248.                 self.selected_griffith = None
  249.         
  250.         if widget == self.tv_csv:
  251.             if iter:
  252.                 self.selected_csv = str(model.get_value(iter, 0))
  253.             else:
  254.                 self.selected_csv = None
  255.                 
  256.         if widget == self.tv_assigned:
  257.             self.iter_assigned = iter
  258.             if self.iter_assigned:
  259.                 self.b_del.set_sensitive(True)
  260.             else:
  261.                 self.b_del.set_sensitive(False)
  262.                 
  263.         # enable add button if both lists have a selected item
  264.         if self.selected_griffith is not None and self.selected_csv is not None:
  265.             self.b_add.set_sensitive(True)
  266.         else:
  267.             self.b_add.set_sensitive(False)
  268.             
  269.     def open_source(self):
  270.         import csv, codecs, os
  271.         # get user values for converting/opening the csv-file
  272.         self.start_row = int(digits_only( self.gtk.get_widget('e_startrow').get_text() ))
  273.         encoding = self.gtk.get_widget('e_encoding').get_active_text()
  274.         encoding = encoding[:string.find( encoding, ' ' )]
  275.         delimiter = self.gtk.get_widget('e_delimiter').get_text()
  276.         if delimiter == '':
  277.             delimiter = ","
  278.         # quotechar
  279.         quotechar =  self.gtk.get_widget('e_quotechar').get_text()
  280.         if quotechar == '':
  281.             quotechar == '"'
  282.         # lineterminator
  283.         active = self.gtk.get_widget('e_lineterminator').get_active()
  284.         # default for none selected and the same for linux and macintosh
  285.         lineterminator = '\r'
  286.         # windows lineterminator
  287.         if active == 1:
  288.             lineterminator = '\r\n'
  289.         
  290.         # open file
  291.         try:
  292.             self.data = csv.reader(codecs.open(self.__source_name, 'r', encoding), dialect='excel', quotechar=quotechar, delimiter=delimiter, lineterminator = lineterminator)
  293.  
  294.             # get the first line in csv file for the field names
  295.             self.csv_header = self.data.next()
  296.             
  297.             # if the user wants to import line 0 then we have to open it again 
  298.             if self.start_row == 0:
  299.                 self.data = csv.reader(codecs.open(self.__source_name, 'r', encoding), dialect='excel', quotechar=quotechar, delimiter=delimiter, lineterminator = lineterminator)
  300.             
  301.         
  302.             # fill the found csv-headers in the simple string list
  303.             self.ls_csv.clear()
  304.             for name in self.csv_header:
  305.                 iterator = self.ls_csv.append()
  306.                 self.ls_csv.set_value(iterator, 0, name)
  307.             return True
  308.         except:
  309.             gutils.info(self.gtk, _("Can't open the file %s") % self.__source_name, self.gtk.get_widget('d_import') )
  310.             return False
  311.             
  312.  
  313.     def set_source(self, name):
  314.         import os
  315.         # source _dependent_ initialization goes here
  316.         if name is None or not os.path.isfile(name):
  317.             return False
  318.         self.__source_name = name
  319.         # auto-detect file-encoding (optional)
  320.         try:
  321.             from chardet.universaldetector import UniversalDetector
  322.             detector = UniversalDetector()
  323.             detector.reset()
  324.             lines = 0
  325.             for line in file(self.__source_name, 'rb'):
  326.                 detector.feed(line)
  327.                 lines += 1
  328.                 if detector.done or lines == 50:
  329.                     break
  330.             detector.close()
  331.             encoding = string.replace( string.lower( detector.result['encoding'] ), '-', '' )
  332.         except:
  333.             encoding = 'utf_8'
  334.         # remove - and _ for better detection
  335.         encoding = string.replace( encoding, '_', '' )
  336.         
  337.         model    = self.gtk.get_widget('e_encoding').get_model()
  338.         itempos    = 0
  339.         for item in model:
  340.             pos1 = string.find( string.replace( string.lower(str(item[0])), '_', '' ) , encoding )
  341.             if pos1 == 0:
  342.                 break
  343.             itempos += 1
  344.         self.gtk.get_widget('e_encoding').set_active(itempos)
  345.         
  346.         # run dialog
  347.         response = self.gtk.get_widget('d_import').run()
  348.         if response == gtk.RESPONSE_OK:
  349.             return True
  350.         else:
  351.             return False
  352.  
  353.     def count_movies(self):
  354.         i = 0
  355.         try:
  356.             import csv
  357.             data = csv.reader(open(self.__source_name))
  358.             while data.next():
  359.                 i += 1
  360.         except:
  361.             return i
  362.     
  363.     def get_movie_details(self):
  364.         try:
  365.             item = self.data.next()
  366.         except:
  367.             return None
  368.         if item is None:
  369.             return None
  370.         import copy
  371.         # start with the right line
  372.         self.current_csv_row += 1
  373.         if (self.current_csv_row ) < self.start_row:
  374.             return None
  375.         
  376.         # assign the keys
  377.         t_movies = copy.deepcopy(self.import_table)
  378.  
  379.         # values are overwritten here with the imports
  380.         for field in self.import_table:
  381.             try:
  382.                 # some minor fixes to the import so it fits the griffith variable types
  383.                 if field == 'year' or field == 'runtime' or field == 'media_num' or field == 'number'  or field == 'volume_id':
  384.                     t_movies[field] = int( digits_only( item[ int(self.import_table[field]) ] ) )
  385.                 elif field == 'seen' or field == 'loaned':
  386.                     t_movies[field] = bool( item[ int(self.import_table[field]) ] )
  387.                 elif field == 'country':
  388.                     t_movies[field] = letters_only( item[ int(self.import_table[field]) ] )
  389.                 elif field == 'cast':
  390.                     try:
  391.                         if item[ int(self.import_table[field]) ].index(", ") != -1:
  392.                             t_movies[field] = string.replace( item[ int(self.import_table[field]) ], ", ", "\n" )
  393.                     except:
  394.                         t_movies[field] = string.replace( item[ int(self.import_table[field]) ], ",", "\n" )
  395.                 else:
  396.                     # 1:1 import
  397.                     t_movies[field] = item[ int(self.import_table[field]) ]
  398.             except:
  399.                 # error field can't be imported
  400.                 t_movies.pop(field)
  401.         
  402.         return t_movies
  403.  
  404.     def clear(self):
  405.         IP.clear(self)
  406.         self.nb_pages.get_nth_page(1).hide()
  407.         self.csv_header = None
  408.         self.ls_assigned.clear()
  409.         self.ls_griffith.clear()
  410.         # add default griffith fields again
  411.         self.set_griffith_fields()
  412.  
  413.     def destroy(self):
  414.         self.gtk.get_widget('d_import').destroy()
  415.